#include "asm_utils.h"
#include "interrupt.h"
#include "stdio.h"
#include "program.h"
#include "thread.h"
#include "sync.h"
#include "memory.h"

// 屏幕IO处理器
STDIO stdio;
// 中断管理器
InterruptManager interruptManager;
// 程序管理器
ProgramManager programManager;
// 内存管理器
MemoryManager memoryManager;

void first_thread(void *arg)
{
    // 第1个线程不可以返回

    //为第一个进程分配 64 页
    //char *process_1 = (char *)memoryManager.allocatePhysicalPages(AddressPoolType::KERNEL, 64);
    //printf("allocate 64 pages for process_1, starting at %d.\n", process_1);

    //为第二个进程分配 32 页
    //char *process_2 = (char *)memoryManager.allocatePhysicalPages(AddressPoolType::KERNEL, 32);
    //printf("allocate 32 pages for process_2, starting at %d.\n", process_2);

    //为第三个进程分配 16 页
    //char *process_3 = (char *)memoryManager.allocatePhysicalPages(AddressPoolType::KERNEL, 16);
    //printf("allocate 16 pages for process_3, starting at %d.\n", process_3);

    //为第四个进程分配 8 页
    //char *process_4 = (char *)memoryManager.allocatePhysicalPages(AddressPoolType::KERNEL, 8);
    //printf("allocate 8 pages for process_4, starting at %d.\n", process_4);

    //释放第一个进程空间
    //memoryManager.releasePhysicalPages(AddressPoolType::KERNEL, int(process_1), 64);
    //printf("release 64 pages of process_1.\n");

    //释放第三个进程空间
    //memoryManager.releasePhysicalPages(AddressPoolType::KERNEL, int(process_3), 64);
    //printf("release 16 pages of process_3.\n");

    //为第五个进程分配 16 页
    //char *process_5 = (char *)memoryManager.allocatePhysicalPages(AddressPoolType::KERNEL, 16);
    //printf("allocate 16 pages for process_5, starting at %d.\n", process_5);

    //为第六个进程分配 64 页。
    //char *process_6 = (char *)memoryManager.allocatePhysicalPages(AddressPoolType::KERNEL, 64);
    //printf("sllocate 64 pages for process_6, starting at %d.\n", process_6);
    

    //assignment 3 test
    //char *process_1 = (char *)memoryManager.FIFO(AddressPoolType::KERNEL, 16);
    //printf("allocate 16 pages for process_1, starting at %d.\n", process_1);

    //char *process_2 = (char *)memoryManager.FIFO(AddressPoolType::KERNEL, 15000);
    //printf("allocate 15000 pages for process_2, starting at %d.\n", process_2);

    //char *process_3 = (char *)memoryManager.FIFO(AddressPoolType::KERNEL, 965);
    //printf("allocate 965 pages for process_3, starting at %d.\n", process_3);

    //char *process_4 = (char *)memoryManager.FIFO(AddressPoolType::KERNEL, 128);
    //printf("allocate 128 pages for process_4, starting at %d.\n", process_4);
    
    
     //assignment 4 test
    char *process_1 = (char *)memoryManager.allocatePages(AddressPoolType::KERNEL, 16);
    printf("allocate 16 pages for process_1, starting at %d.\n", process_1);

    char *process_2 = (char *)memoryManager.allocatePages(AddressPoolType::KERNEL, 512);
    printf("allocate 512 pages for process_2, starting at %d.\n", process_2);

    char *process_3 = (char *)memoryManager.allocatePages(AddressPoolType::KERNEL, 256);
    printf("allocate 256 pages for process_3, starting at %d.\n", process_3);
    
    memoryManager.releasePages(AddressPoolType::KERNEL, int(process_1), 16);
    printf("release 16 pages of process_1.\n");
    
    memoryManager.releasePages(AddressPoolType::KERNEL, int(process_3), 256);
    printf("release 256 pages of process_3.\n");

    char *process_4 = (char *)memoryManager.allocatePages(AddressPoolType::KERNEL, 128);
    printf("allocate 128 pages for process_4, starting at %d.\n", process_4);



    asm_halt();
}

extern "C" void setup_kernel()
{

    // 中断管理器
    interruptManager.initialize();
    interruptManager.enableTimeInterrupt();
    interruptManager.setTimeInterrupt((void *)asm_time_interrupt_handler);

    // 输出管理器
    stdio.initialize();

    // 进程/线程管理器
    programManager.initialize();

    // 内存管理器
    memoryManager.openPageMechanism();
    memoryManager.initialize();

    // 创建第一个线程
    int pid = programManager.executeThread(first_thread, nullptr, "first thread", 1);
    if (pid == -1)
    {
        printf("can not execute thread\n");
        asm_halt();
    }

    ListItem *item = programManager.readyPrograms.front();
    PCB *firstThread = ListItem2PCB(item, tagInGeneralList);
    firstThread->status = RUNNING;
    programManager.readyPrograms.pop_front();
    programManager.running = firstThread;
    asm_switch_thread(0, firstThread);

    asm_halt();
}

